{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Restricting reactions to a part of a region" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A version of this notebook may be run online via Google Colab at https://tinyurl.com/neuron-restricted-reaction\n", " (make a copy or open in playground mode)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "\n", "Reactions may be restricted to only occur in a given part of an `rxd.Region` by multiplying the rate by an indicator variable, that is an `rxd.Parameter` that takes the value `1` in the subregion where the reaction is to occur and `0` elsewhere.\n", "\n", "Let's consider an example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup NEURON library and imports" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's import our usual NEURON libraries and definitions. Remember you can use either `um` or `µm` for micron.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:14.650564Z", "iopub.status.busy": "2025-08-18T03:36:14.650406Z", "iopub.status.idle": "2025-08-18T03:36:15.049552Z", "shell.execute_reply": "2025-08-18T03:36:15.049146Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from neuron import n, rxd\n", "from neuron.units import mV, ms, um, mM\n", "\n", "## needed for standard run system\n", "n.load_file(\"stdrun.hoc\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now import `plotly`, a graphics library. (You could easily modify this code to use other graphics libraries like `matplotlib`, `plotnine`, or `bokeh`.)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.114592Z", "iopub.status.busy": "2025-08-18T03:36:15.114335Z", "iopub.status.idle": "2025-08-18T03:36:15.122572Z", "shell.execute_reply": "2025-08-18T03:36:15.122191Z" } }, "outputs": [], "source": [ "import plotly.graph_objects as go" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup the model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Morphology and discretization" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.126499Z", "iopub.status.busy": "2025-08-18T03:36:15.124269Z", "iopub.status.idle": "2025-08-18T03:36:15.132738Z", "shell.execute_reply": "2025-08-18T03:36:15.132409Z" } }, "outputs": [ { "data": { "text/plain": [ "right" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "left = n.Section(name=\"left\")\n", "right = n.Section(name=\"right\")\n", "\n", "left.nseg = right.nseg = 101\n", "left.L = right.L = 101\n", "\n", "right.connect(left)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The rxd.Region" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Our region will be present on both the `left` and the `right` sections. Since they define our entire \"cell\", we will pick one and put the `rxd.Region` on the `.wholetree()` that is connected to it." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.134337Z", "iopub.status.busy": "2025-08-18T03:36:15.134198Z", "iopub.status.idle": "2025-08-18T03:36:15.138516Z", "shell.execute_reply": "2025-08-18T03:36:15.138137Z" } }, "outputs": [], "source": [ "cytosol = rxd.Region(left.wholetree())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The rxd.Species" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's begin by defining our initialization rule. The concentration will initially be 0 everywhere except for nodes between 90 and 110 microns from the left edge of `left` (that is, the last 10 microns of `left` and the first 10 microns of `right`)." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.141957Z", "iopub.status.busy": "2025-08-18T03:36:15.141811Z", "iopub.status.idle": "2025-08-18T03:36:15.144724Z", "shell.execute_reply": "2025-08-18T03:36:15.144413Z" } }, "outputs": [], "source": [ "def initial_protein(node):\n", " if 90 * um < n.distance(node, left(0)) < 110 * um:\n", " return 1 * mM\n", " else:\n", " return 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the species definition itself." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.146245Z", "iopub.status.busy": "2025-08-18T03:36:15.146112Z", "iopub.status.idle": "2025-08-18T03:36:15.153522Z", "shell.execute_reply": "2025-08-18T03:36:15.153140Z" } }, "outputs": [], "source": [ "protein = rxd.Species(cytosol, d=1, initial=initial_protein)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The rxd.Reaction and its localization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We need an `rxd.Parameter` indicator variable to indicate the sections where the reaction is to take place. In parallel to how we defined the initial concentration of the species above, it is often simplest to define the values using a function of the node (here 1 in the `right` section; 0 otherwise):" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.155170Z", "iopub.status.busy": "2025-08-18T03:36:15.155028Z", "iopub.status.idle": "2025-08-18T03:36:15.157765Z", "shell.execute_reply": "2025-08-18T03:36:15.157412Z" } }, "outputs": [], "source": [ "def active_region_value(node):\n", " if node in right:\n", " return 1\n", " else:\n", " return 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the indicator variable `rxd.Parameter` itself:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.160627Z", "iopub.status.busy": "2025-08-18T03:36:15.160484Z", "iopub.status.idle": "2025-08-18T03:36:15.165492Z", "shell.execute_reply": "2025-08-18T03:36:15.165136Z" } }, "outputs": [], "source": [ "in_region = rxd.Parameter(cytosol, value=active_region_value)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the reaction (here an `rxd.Rate` but could be an `rxd.Reaction` or `rxd.MultiCompartmentReaction` as well), note that we multiply by the value of `in_region`, so when that value is `1` the reaction happens and when it is `0`, the reaction does not." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.167094Z", "iopub.status.busy": "2025-08-18T03:36:15.166949Z", "iopub.status.idle": "2025-08-18T03:36:15.169551Z", "shell.execute_reply": "2025-08-18T03:36:15.169181Z" } }, "outputs": [], "source": [ "production_rate = 0.002 * mM / ms" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.171826Z", "iopub.status.busy": "2025-08-18T03:36:15.171681Z", "iopub.status.idle": "2025-08-18T03:36:15.176501Z", "shell.execute_reply": "2025-08-18T03:36:15.176138Z" } }, "outputs": [], "source": [ "reaction = rxd.Rate(protein, production_rate * in_region)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run and visualize the simulation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Always initialize your simulations." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.178175Z", "iopub.status.busy": "2025-08-18T03:36:15.178034Z", "iopub.status.idle": "2025-08-18T03:36:15.847858Z", "shell.execute_reply": "2025-08-18T03:36:15.847444Z" } }, "outputs": [ { "data": { "text/plain": [ "1.0" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "n.finitialize(-65 * mV)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll plot the protein concentrations against their distance from the left edge of the left section (i.e. from `left(0)`)." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.850329Z", "iopub.status.busy": "2025-08-18T03:36:15.849563Z", "iopub.status.idle": "2025-08-18T03:36:15.854755Z", "shell.execute_reply": "2025-08-18T03:36:15.854402Z" } }, "outputs": [], "source": [ "def plot(fig):\n", " y = protein.nodes.concentration\n", " x = [n.distance(node, left(0)) for node in protein.nodes]\n", " fig.add_trace(go.Scatter(x=x, y=y, name=f\"t = {n.t:g} ms\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Plot the initial conditions, then advance for 25 ms, plot, advance again, etc." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2025-08-18T03:36:15.861090Z", "iopub.status.busy": "2025-08-18T03:36:15.858420Z", "iopub.status.idle": "2025-08-18T03:36:16.502651Z", "shell.execute_reply": "2025-08-18T03:36:16.502257Z" } }, "outputs": [ { "data": { "text/html": [ " \n", " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "